/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	AABB.cpp
*
*	Comments	-	See AABB.h
*
**************************************************************************************/
#include "../Include/AABB.h"
#include "../Include/PTLBase.h"

namespace Pulse
{
	AABB::AABB( void )
	{
		Reset();
	}

	AABB::~AABB( void )
	{

	}

	AABB & AABB::Reset( void )
	{
		m_min = Vector3::MIN_VECTOR;
		m_max = Vector3::MAX_VECTOR;

		return *this;
	}

	AABB & AABB::ContainPoint( Vector3 *pPoint )
	{
		if ( pPoint->x < m_min.x ) m_min.x = pPoint->x;
		if ( pPoint->y < m_min.y ) m_min.y = pPoint->y;
		if ( pPoint->z < m_min.z ) m_min.z = pPoint->z;

		if ( pPoint->x > m_max.x ) m_max.x = pPoint->x;
		if ( pPoint->y > m_max.y ) m_max.y = pPoint->y;
		if ( pPoint->z > m_max.z ) m_max.z = pPoint->z;

		return *this;
	}

	AABB & AABB::Translate( Vector3 *pTranslate )
	{
		m_min.x += pTranslate->x;
		m_min.y += pTranslate->y;
		m_min.z += pTranslate->z;

		m_max.x += pTranslate->x;
		m_max.y += pTranslate->y;
		m_max.z += pTranslate->z;

		return *this;
	}

	AABB & AABB::Transform( Matrix4x4 *pTransform )
	{
		// transform to world space
		Vector3 center = (m_min + m_max) * 0.5f;
		const Vector3 extentX = pTransform->vec3Row1 * (m_max.x - center.x);
		const Vector3 extentY = pTransform->vec3Row2 * (m_max.y - center.y);
		const Vector3 extentZ = pTransform->vec3Row3 * (m_max.z - center.z);

		// calculate axis-aligned extents
		const FLOAT AAEX = PSX_Abs(extentX.x) + PSX_Abs(extentY.x) + PSX_Abs(extentZ.x);
		const FLOAT AAEY = PSX_Abs(extentX.y) + PSX_Abs(extentY.y) + PSX_Abs(extentZ.y);
		const FLOAT AAEZ = PSX_Abs(extentX.z) + PSX_Abs(extentY.z) + PSX_Abs(extentZ.z);
		
		// Compute new center. Include rotation and scale.
		// We can actually just do a normal transform but we save a bit of
		// clock cycles by preventing 4 redundant multiplication operations.
		center = center.TransformNormal( *pTransform );

		// Construct new axis-aligned bounding box. Also add translation.
		center = center + pTransform->vec3Row4;
		m_min.x = center.x - AAEX;
		m_min.y = center.y - AAEY;
		m_min.z = center.z - AAEZ;
		m_max.x = center.x + AAEX;
		m_max.y = center.y + AAEX;
		m_max.z = center.z + AAEX;

		return *this;
	}

	BOOL AABB::TestAABB( const AABB *pAABB ) const
	{
		return (m_min.x <= pAABB->m_max.x) && (m_min.y <= pAABB->m_max.y) && (m_min.z <= pAABB->m_max.z) && 
			(m_max.x >= pAABB->m_min.x) && (m_max.y >= pAABB->m_min.y) && ( m_max.z >= pAABB->m_max.z);
	}

	BOOL AABB::TestPoint( Vector3 *pPoint ) const
	{
		if ( pPoint->x < m_min.x || pPoint->y < m_min.y || pPoint->z < m_min.z ||
			pPoint->x > m_max.x || pPoint->y > m_max.y || pPoint->z > m_max.z )
			return FALSE;
		
		return TRUE;
	}
}